#include <iostream>
#include <memory>
#include <vector>
#include <limits>
#include <algorithm>
#include <unistd.h>
#include <chrono>
#include <list>
#include <forward_list>
#include <set>
#include <cstring>
#include <map>
#include <unordered_map>

using namespace std;
struct Student{
    int id;
    int age;
    string name;
    bool operator < (const Student& s) const{
        return id < s.id;
    }

};
ostream& operator<<(ostream& os, const Student& student){
    os<<"Student-id: "<<student.id<<", name:"<<student.name<<"]";
    return os;
}
struct Message{
    int code;
    string msg;
};
ostream& operator<<(ostream& os, const Message& msg){
    os<<"Message:"<<msg.msg;
    return os;
}

struct StudentHash{
    size_t operator()(const Student& student) const{
        return student.id;
    }
};

struct StudentCmp{
    bool operator()(const Student& s1, const Student& s2) const{
        return s1.id == s2.id;
    }
};





template<typename T, typename V>
ostream& operator << (ostream& os, const pair<T,V> p){
    os << "[" << p.first << ", " << p.second << "]";
    return os;
}

template<typename T, typename V, typename C>
void printMap(const char* s, map<T, V, C>& m){
    cout<<s<<": ";
    for (auto& i : m){
        cout<<i<<" ";
    }
    cout<<endl;
}

template<typename T>
void print_iterable(const char* s, T& t){
    cout<<s<<": ";
    for (auto& i : t)
        cout<<i<<" ";
    cout<<endl;
}

struct my_string_less{
    bool operator()(const string& s1, const string& s2) const{
        return s1>s2;
    }
};
int main(){
    auto myset = set<string, my_string_less>();
    myset.insert("123");
    myset.insert("678");
    myset.insert("456");
    print_iterable("After init", myset);

    auto cmp = myset.key_comp();
    cout<<cmp("1","2")<<" "<<cmp("2", "1")<<endl;

    myset.insert("456");
    myset.insert("456");

    auto myMultiset = multiset<string, my_string_less>({"123","213","123","123","345"});
    cout<<"count: "<<myMultiset.count("123")<<endl;

    auto seti = set<int>({5,6,8,9,11});
    cout<<*seti.lower_bound(4)<<endl;
    cout<<*seti.lower_bound(5)<<endl;
    cout<<*seti.upper_bound(5)<<endl;


    cout<<"------------------------------"<<endl;
    map<int, string, greater<int>> mymap;
    mymap.insert(pair<int, string>(11,"11"));
    mymap[12] = "12";
    printMap("After insert", mymap);
    if (mymap.find(12) == mymap.end())
        cout<<"Cannot find"<<endl;
    else cout<<"Found"<<endl;


    cout<<"------------------------------"<<endl;

    unordered_map<Student, Message, StudentHash, StudentCmp> studentMessage;

    Student a{0,0,"name1"};
    Message m{1,"message1"};
    studentMessage[a] = m;
    Student b{1,0,"Name2"};
    Message m2{2,"message2"};
    studentMessage[b] = m2;

    print_iterable("self defined", studentMessage);


}
